package com.northpool.operator.analysis.overlap;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.northpool.geometry.Operator;
import com.northpool.geometry.OperatorFactoryLocal;
import com.northpool.geometry.OperatorImportFromGeoJson;
import com.northpool.geometry.Polygon;
import com.northpool.geometry.ogc.OGCGeometry;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.common.algorithm.OperatorTestBuild;
import com.northpool.operator.common.algorithm.TestParamBuilder;
import com.northpool.operator.common.database.DatabaseUtils;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.operator.utils.ServeOperatorHelper;
import com.northpool.resources.command.Constants;
import com.northpool.resources.command.QueryFilter;
import com.northpool.resources.datasource.IDataSource;
import com.northpool.resources.datatable.FieldEncoder;
import com.northpool.resources.datatable.ITable;
import com.northpool.resources.datatable.SpatialInfo;
import com.northpool.spatial.Geom;
import com.northpool.spatial.utils.GeodesicAreaUtils;
import com.northpool.spatial.utils.GeomUtils;
import org.locationtech.jts.geom.Geometry;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@OperatorInfo(ref = "LinkQueryServeOperator",
        name = "关联查询",
        description = "关联图层的范围查询;多年的数据表需在同一个数据源中",
        version = "serve-1.0.0"
)
public class LinkQueryServeOperator extends ServeOperatorHelper {

    @InputParams({
            @InputParam(ref = "port", name = "服务端口", desc = "服务端口", type = TypeEnum.NUMBER, required = false, value = "12402"),
            @InputParam(ref = "dataSourceId", name = "数据源ID", desc = "数据源ID", type = TypeEnum.DATASOURCE, required = true),
            @InputParam(ref = "tableNames", name = "多年份表", desc = "多年分数据列表多行填写，{年份}|{图层名} : public.dltb2021", required = true),
            @InputParam(ref = "fields", name = "字段过滤", desc = "数据字段列表，多个逗号隔开，如: f_id,dlmc,dlbm", required = true),
            @InputParam(ref = "areaThreshold", name = "最小面积阈值", desc = "过滤相交低于此值的数据", value = "0.001", type = TypeEnum.NUMBER, required = false),
    })
    public LinkQueryServeOperator(ParamTool paramTool) {
        super(paramTool.getNumber("port").intValue());
    }

    public static void main(String[] args) throws Exception {
        OperatorTestBuild.execute(
                LinkQueryServeOperator.class, TestParamBuilder.aBuilder()
                        .param("dataSourceId", "402881ac934fb41701934fc212af000b")
//                        .param("geojson", "{\"type\":\"Polygon\",\"coordinates\":[[[113.461530909784,28.3523478507744],[113.461556840082,28.3523708991621],[113.461611015013,28.3524229938291],[113.461688466918,28.3524926377772],[113.46171343381,28.3525407657692],[113.461705197216,28.3525567309059],[113.461710052187,28.3525753571042],[113.4616952699,28.3525642690717],[113.461626231777,28.3525053598725],[113.46160295105,28.3525253150727],[113.461680625062,28.3525865070876],[113.461711351793,28.352609377124],[113.46175649819,28.3526387197906],[113.461784265052,28.3526530582192],[113.461809569839,28.3526641519626],[113.461861998874,28.3526826411109],[113.461901656183,28.3526925171395],[113.461935396974,28.3526989937863],[113.462036434957,28.3527144171354],[113.462129744779,28.3527284318498],[113.462160044154,28.3527343999534],[113.462187831199,28.3527418792384],[113.462277596229,28.3527763871526],[113.462299967137,28.3527835118228],[113.462308886199,28.3527854361137],[113.462338357062,28.3527907602468],[113.462347818783,28.3527919362486],[113.462391258862,28.3527924180692],[113.46241692513,28.3527891789997],[113.462557886886,28.3527560518549],[113.462612818817,28.352744639165],[113.462658408003,28.3527367849412],[113.462697280873,28.3527319932167],[113.462731805174,28.3527294317855],[113.462774196852,28.3527283427826],[113.462897274797,28.3527279069978],[113.462935348106,28.3527258442482],[113.462974706031,28.3527211289336],[113.46304902321,28.3527068762054],[113.463103998072,28.3526913891066],[113.463138542143,28.3526776389007],[113.463220213846,28.3526394320296],[113.463245297006,28.3526292447802],[113.463269008879,28.3526216359235],[113.463301176801,28.3526159442053],[113.463325399884,28.3526100771674],[113.463348056151,28.3526123158849],[113.46336334907,28.3526302810967],[113.463405899935,28.3527013530905],[113.463448405946,28.3527817349567],[113.46344751312,28.3527982038976],[113.463436881187,28.35281964777],[113.463400225237,28.352863909061],[113.463298645208,28.3529257898872],[113.463269918029,28.3529450272243],[113.46323213284,28.352972507084],[113.463104652178,28.3530734979461],[113.462986858513,28.3531592859246],[113.462957100909,28.3531809581754],[113.462884847831,28.3532422070332],[113.462693452815,28.3534149818442],[113.462647801105,28.3534545499723],[113.462536298244,28.3535434362297],[113.462444002819,28.3536110918379],[113.46238974606,28.3536458761079],[113.46235799808,28.3536629038909],[113.462329211783,28.3536756048786],[113.462272753989,28.3536953860747],[113.462237915076,28.3537051849519],[113.46217884016,28.3537176689805],[113.462042757985,28.3537315832323],[113.461993685797,28.3537403119117],[113.461955778178,28.3537501650853],[113.461924163982,28.3537609111742],[113.461895500816,28.3537726167892],[113.461770713179,28.3538306362452],[113.461729355787,28.3538515922458],[113.461676135132,28.3538822808909],[113.461645852883,28.3539019502425],[113.461616525972,28.3539226380696],[113.461575363986,28.353956120797],[113.461546429794,28.3539863541556],[113.461528984816,28.3540080252233],[113.461412212844,28.354169370082],[113.461326494201,28.3542843272444],[113.461302955764,28.3543137630875],[113.461270411163,28.3543486278054],[113.46124342877,28.3543704668766],[113.461158444067,28.354424853835],[113.460892855052,28.3545853661039],[113.460819437156,28.3546505957763],[113.460501566971,28.3549490499534],[113.460184482203,28.3552801338786],[113.459814589194,28.3556570031428],[113.459796420541,28.355678691172],[113.459767770733,28.355712890625],[113.459742461969,28.3557431019568],[113.459560144083,28.355924602751],[113.459554412975,28.3559324241903],[113.45955122915,28.3559334762385],[113.459524404816,28.3559368368994],[113.459517094209,28.3559354020215],[113.459511572942,28.3559324350265],[113.459453277984,28.3558711921508],[113.4593595061,28.3557743790931],[113.459295430464,28.355712890625],[113.459247092029,28.3556665039401],[113.459217015237,28.3556344829547],[113.459189852235,28.3556317587605],[113.459166080795,28.3556272951552],[113.459133390955,28.3556298689751],[113.45904477686,28.3556219978481],[113.458990555959,28.3556171268673],[113.458968349981,28.3556055792162],[113.458947772905,28.3555922482133],[113.458926020988,28.3555740202445],[113.458924240138,28.3555699549401],[113.4589207838,28.355561286154],[113.458917353864,28.3555525619496],[113.458913725844,28.3555438942257],[113.45891325183,28.3555428350377],[113.458909184058,28.3555343461717],[113.458906793764,28.3555298650307],[113.458909060776,28.3554875039373],[113.458919486215,28.3554465681051],[113.459268059877,28.355041147115],[113.459272940878,28.3550332290269],[113.45927454221,28.3550341810073],[113.459372486939,28.3551055038128],[113.459481843837,28.3550103828396],[113.459620073945,28.3548685848003],[113.459620492022,28.354868190074],[113.459734349114,28.3547668941706],[113.459738112948,28.3547143269167],[113.459722002765,28.3546646941355],[113.459721752777,28.3546606808769],[113.459737448764,28.3545796080726],[113.459742014092,28.354573525892],[113.459801134174,28.3545401439522],[113.459801740902,28.3545398269462],[113.459834949981,28.3545238242072],[113.459916658187,28.3544880868602],[113.459917211161,28.3544878622165],[113.459917705931,28.354487691075],[113.460001676852,28.3544607921349],[113.460127320164,28.354412063929],[113.460263235207,28.3543301968065],[113.460263684214,28.35432995108],[113.460408689908,28.3542552650282],[113.460409301116,28.3542549750653],[113.460494564806,28.3542176829768],[113.460571431005,28.3541853167743],[113.460573326062,28.354184714045],[113.460684046248,28.3541600661294],[113.460685843982,28.3541598137524],[113.460881234118,28.3541480639759],[113.460996602054,28.3541342102028],[113.461102116779,28.3540687170489],[113.461169260752,28.3540177039006],[113.461172567806,28.3540160231254],[113.46133629924,28.3539658570253],[113.461379421007,28.3539242708659],[113.461402103957,28.3538997059367],[113.46137577883,28.3538808207641],[113.461379365837,28.3538717772042],[113.461382479139,28.3538453810951],[113.461381370753,28.3538286172457],[113.461378569811,28.353811240882],[113.461367120815,28.3537721800471],[113.461351664906,28.3537408688955],[113.461336749196,28.3537221269272],[113.461321813848,28.3537114440899],[113.46131755601,28.353710085821],[113.461323028868,28.3537061418253],[113.46140402284,28.3536815959832],[113.461554219863,28.3536280140359],[113.461554726241,28.3536278462201],[113.461598348247,28.3536146173993],[113.461677055007,28.3535907478355],[113.461707718971,28.3535660120739],[113.461721864319,28.3535366006078],[113.461731600115,28.3535163570967],[113.46173378609,28.3535134981558],[113.461746005822,28.3535027262069],[113.461825681775,28.3534324908321],[113.461805579801,28.3534038191256],[113.461788552957,28.3533769638348],[113.461788188955,28.3533763317626],[113.461772219244,28.3533457239195],[113.461771915874,28.3533450748944],[113.461771712201,28.3533445418146],[113.461771083117,28.3533426901666],[113.461742651255,28.3533630897085],[113.461573958039,28.3534841210055],[113.461565768192,28.3534859998742],[113.461380565758,28.3534572031362],[113.461375726849,28.3534551919414],[113.46129561988,28.353394975192],[113.461293177166,28.3533922660272],[113.46125121418,28.3533209672328],[113.461250198197,28.3533153240385],[113.461259243785,28.3532670893763],[113.461271946135,28.3531993489701],[113.461272792836,28.353196959192],[113.461336453004,28.3530782000874],[113.461365795897,28.3529763039141],[113.461354066961,28.3529231950201],[113.461310197075,28.3528411057733],[113.461208274165,28.3528045730078],[113.461204646113,28.3528023641441],[113.461137255056,28.3527384522425],[113.461134716007,28.3527340860737],[113.461109872783,28.3526254160081],[113.461110602186,28.3526198570611],[113.461153339977,28.3525376602129],[113.461156093785,28.3525344870442],[113.461338750906,28.352400430141],[113.461342288205,28.3523987432093],[113.461530909784,28.3523478507744]],[[113.461850245085,28.3528295911334],[113.46179882719,28.3528639832256],[113.461675275177,28.353009145047],[113.461727669201,28.3531086248807],[113.461992194871,28.3530438179026],[113.462213669054,28.3530076880057],[113.462206193137,28.352884710105],[113.462035101007,28.3528303207928],[113.461850245085,28.3528295911334]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:4326\"}}}")
                        .param("fields", "dlmc,dlbm,geom")
                        .param("tableNames", "2020年|2020年地类图斑:public.dltb2022_4301\n" +
                                "2021年|2021年地类图斑:public.dltb2022_4301\n" +
                                "2022年|2022年地类图斑:public.dltb2022_4301\n" +
                                "2023年|2023年地类图斑:public.dltb2022_4301\n" +
                                "2024年|2024年地类图斑:public.dltb2022_4301")
                        .build());
    }

    @Override
    public void execute(ParamTool paramTool) throws Exception {
        String dataSourceId = paramTool.getStr("dataSourceId");
        String tableNames = paramTool.getStr("tableNames");
        String fieldsStr = paramTool.getStr("fields");
        String[] fields = StrUtil.splitTrim(fieldsStr, ",").toArray(new String[0]);
        String[] lines = tableNames.split("\\R");// 按行提取表名

        String dataSourceJson = DatabaseUtils.getDataSourceJson(dataSourceId);
//        dataSourceJson = dataSourceJson.replace("192.168.1.", "192.168.164.");
        IDataSource ds = IDataSource.fromJSON(dataSourceJson);
        try {
            ds.testConnection();
        } catch (Exception ex) {
            this.error("数据库连接失败: {}",ExceptionUtil.getMessage(ex));
            this.failedExit();
        }
        Map<String, String> layerMap = new LinkedHashMap<>();
        Map<String, String> yearMap = new LinkedHashMap<>();
        for (String line : lines) {
            String trim = line.trim();
            if (StrUtil.isBlank(trim)) continue;
            String[] split = trim.split(":");
            if (split.length != 2) {
                throw new RuntimeException("参数中 {年份}|{图层名} : {表名} 规则和预期不一致");
            }
            String[] yearAndLayer = split[0].trim().split("\\|");
            String year = yearAndLayer[0];
            String layer = yearAndLayer.length == 2 ? yearAndLayer[1] : year;
            String tableName = split[1].trim();
            layerMap.put(layer, tableName);
            yearMap.put(layer, year);
            this.log(year, layer, tableName);
        }

        this.addEndpoint("/query", Method.POST,  session -> {
            Map<String, Object> bodyParams = session.getBodyParams();
            String geojson = bodyParams.get("geojson").toString();
            String layersStr = bodyParams.get("layers").toString();
            BigDecimal areaThreshold = (BigDecimal) paramTool.get("areaThreshold").getValue();

            OperatorImportFromGeoJson importerGeoJson = (OperatorImportFromGeoJson) OperatorFactoryLocal.getInstance().getOperator(Operator.Type.ImportFromGeoJson);
            Polygon polygon = (Polygon) (importerGeoJson.execute(0, com.northpool.geometry.Geometry.Type.Unknown, geojson, null).getGeometry());
            Geom geom = new Geom(com.northpool.spatial.Constants.SPATIAL_TYPE.esriGeometry
                    ,OGCGeometry.createFromEsriGeometry(polygon, null));

            geom.changeType(com.northpool.spatial.Constants.SPATIAL_TYPE.esriGeometry);
            Geometry jtsGeometry = geom.toJTSGeometry();
            String wkt = jtsGeometry.toText();

            List<String> queryList = StrUtil.split(layersStr, ",");
            List<Map<String, String>> resultList = new CopyOnWriteArrayList<>(); // 改为线程安全集合
            queryList.parallelStream().forEach(layer -> {
                try {
                    if (!layerMap.containsKey(layer)) {
                        return;
                    }
                    String dataTable = layerMap.get(layer);
                    ITable tb = ds.getTable(dataTable, FieldEncoder.ORIGIN_FIELD_ENCODER);
                    SpatialInfo spatialInfo = tb.spatialInfo();
                    String fieldName = spatialInfo.getOriginFieldName();
                    QueryFilter filter = new QueryFilter();
                    filter.addFilter(fieldName, Constants.OPERATION.INTERSECTS, wkt);
                    filter.setSRID(spatialInfo.getSrid());
                    filter.setOutputFieldNames(fields);
                    List<Map<String, Object>> features = tb.mapDao().query(filter);
                    this.log("{} 查询命中：{}", layer, features.size());
                    AtomicInteger count = new AtomicInteger();
                    AtomicReference<Double> overlapArea = new AtomicReference<>((double) 0);
                    Map<String, String> row = new LinkedHashMap<>();
                    features.stream().parallel().forEach(item -> {
                        for (String field : fields) {
                            Object object = item.get(field);
                            if (object instanceof Geom) {
                                Geom itemGeom = (Geom) object;
                                itemGeom.changeType(com.northpool.spatial.Constants.SPATIAL_TYPE.esriGeometry);
                                // 相交计算
                                Geom intersection = GeomUtils.getIntersection(geom, itemGeom);
                                if (intersection.isEmpty()) { // 如果不相交就跳过
                                    return;
                                }
                                double area = GeodesicAreaUtils.calculate(intersection.toJTSGeometry());
                                if (NumberUtil.compare(area, areaThreshold.doubleValue()) < 1) {
                                    return; // 小于阈值不统计，屏蔽碎图斑的影响
                                }
                                count.getAndIncrement();
                                overlapArea.updateAndGet(v -> v + area);
                                break;
                            }
                        }
                    });
                    row.put("year", yearMap.get(layer));
                    row.put("layerName", layer);
                    row.put("featureCount", NumberUtil.toStr(count.get()));
                    row.put("overlapArea", NumberUtil.toStr(overlapArea.get()));
                    resultList.add(row);

                } catch (Exception ex) {
                    String message = ExceptionUtil.getMessage(ex);
                    error(message);
                }
            });
            resultList.sort((o1, o2) -> StrUtil.compare(o1.get("year"), o2.get("year"), true));
            return resultList;
        });

    }
}
